package syscompat

import (
	"errors"
	"fmt"
	"strings"

	"github.com/shirou/gopsutil/v3/host"

	"gopkg.openfuyao.cn/bkeadm/pkg/global"
	"gopkg.openfuyao.cn/bkeadm/utils/log"
)

// Compat Compatible with multiple system Settings
func Compat() error {
	h, _ := host.Info()
	// stop firewall
	_ = global.Command.ExecuteCommand("sudo", "systemctl", "stop", "firewalld")
	_ = global.Command.ExecuteCommand("sudo", "systemctl", "disable", "firewalld")
	_ = global.Command.ExecuteCommand("sudo", "ufw", "disable")

	// iptables
	output, err := global.Command.ExecuteCommandWithOutput("iptables", "-V")
	if err != nil {
		log.BKEFormat(log.WARN, fmt.Sprintf("iptables -V error: %s", err.Error()))
		if strings.Contains(err.Error(), "not found") {
			switch strings.ToLower(h.Platform) {
			case "centos", "kylin", "openeuler":
				log.BKEFormat(log.INFO, "install iptables...")
				err = global.Command.ExecuteCommand("yum", "-y", "install", "iptables")
				if err != nil {
					log.BKEFormat(log.ERROR, fmt.Sprintf("Failed to install iptables, %s", err.Error()))
					return nil
				}
				output, err = global.Command.ExecuteCommandWithOutput("iptables", "-V")
				if err != nil {
					log.BKEFormat(log.ERROR, fmt.Sprintf("Failed to exec iptables -V, %s", err.Error()))
					return nil
				}
			case "ubuntu", "debian", "fedora":
				log.BKEFormat(log.INFO, "install iptables...")
				_ = global.Command.ExecuteCommand("apt", "-y", "clean")
				_ = global.Command.ExecuteCommand("apt", "-y", "update")
				err = global.Command.ExecuteCommand("apt", "-y", "install", "iptables")
				if err != nil {
					log.BKEFormat(log.ERROR, fmt.Sprintf("Failed to install iptables, %s", err.Error()))
					return nil
				}
				output, err = global.Command.ExecuteCommandWithOutput("iptables", "-V")
				if err != nil {
					log.BKEFormat(log.ERROR, fmt.Sprintf("Failed to exec iptables -V, %s", err.Error()))
					return nil
				}
			default:
				log.BKEFormat(log.ERROR, "Unsupported platform, only support centos, ubuntu, debian, fedora")
				return nil
			}
		} else {
			return err
		}
	}
	log.BKEFormat(log.INFO, fmt.Sprintf("iptables -V output: %s", output))
	if strings.Contains(output, "nf_tables") {
		switch strings.ToLower(h.Platform) {
		case "centos", "kylin", "openeuler":
			err = global.Command.ExecuteCommand("yum", "-y", "remove", "iptables")
			if err != nil {
				log.BKEFormat(log.ERROR, fmt.Sprintf("Failed to remove iptables, %s", err.Error()))
				return err
			}
			err = global.Command.ExecuteCommand("yum", "-y", "install", "iptables")
			if err != nil {
				log.BKEFormat(log.ERROR, fmt.Sprintf("Failed to install iptables, %s", err.Error()))
				return err
			}
		case "ubuntu", "debian":
			err = global.Command.ExecuteCommand("update-alternatives", "--set", "iptables", "/usr/sbin/iptables-legacy")
			if err != nil {
				log.BKEFormat(log.WARN, fmt.Sprintf("Failed to update iptables, %s", err.Error()))
				return nil
			}
			err = global.Command.ExecuteCommand("update-alternatives", "--set", "ip6tables", "/usr/sbin/ip6tables-legacy")
			if err != nil {
				log.BKEFormat(log.WARN, fmt.Sprintf("Failed to update ip6tables, %s", err.Error()))
				return nil
			}
			err = global.Command.ExecuteCommand("update-alternatives", "--set", "arptables", "/usr/sbin/arptables-legacy")
			if err != nil {
				log.BKEFormat(log.WARN, fmt.Sprintf("Failed to update arptables, %s", err.Error()))
				return nil
			}
			err = global.Command.ExecuteCommand("update-alternatives", "--set", "ebtables", "/usr/sbin/ebtables-legacy")
			if err != nil {
				log.BKEFormat(log.WARN, fmt.Sprintf("Failed to update ebtables, %s", err.Error()))
				return nil
			}
		case "fedora":
			err = global.Command.ExecuteCommand("update-alternatives", "--set", "iptables", "/usr/sbin/iptables-legacy")
			if err != nil {
				log.BKEFormat(log.WARN, fmt.Sprintf("Failed to update iptables, %s", err.Error()))
				return nil
			}
		default:
			return errors.New(fmt.Sprintf("%s is not supported", h.Platform))
		}
	}
	return nil
}

func RepoUpdate() error {
	packageManager := ""
	h, _, _, err := host.PlatformInformation()
	if err != nil {
		log.Errorf("get host platform information failed, err: %v", err)
	}
	switch h {
	case "ubuntu", "debian":
		packageManager = "apt"
	case "centos", "kylin", "redhat", "fedora", "openeuler", "hopeos":
		packageManager = "yum"
	default:
		packageManager = "unknown"
	}
	switch packageManager {
	case "apt":
		output, err := global.Command.ExecuteCommandWithCombinedOutput("/bin/sh", "-c", fmt.Sprintf("%s -y clean", packageManager))
		if err != nil {
			log.Errorf("update packages failed, err: %v, out: %s", err, output)
			return nil
		}

		output, err = global.Command.ExecuteCommandWithCombinedOutput("/bin/sh", "-c", fmt.Sprintf("%s -y update", packageManager))
		if err != nil {
			log.Errorf("update packages failed, err: %v, out: %s", err, output)
			return nil
		}
	case "yum":
		// yum clean all
		output, err := global.Command.ExecuteCommandWithCombinedOutput("/bin/sh", "-c", fmt.Sprintf("%s clean all", packageManager))
		if err != nil {
			log.Errorf("update packages failed, err: %v, out: %s", err, output)
			return nil
		}
		// yum makecache
		output, err = global.Command.ExecuteCommandWithCombinedOutput("/bin/sh", "-c", fmt.Sprintf("%s makecache", packageManager))
		if err != nil {
			return nil
		}
	default:
		log.Errorf("package manager %q not supported", packageManager)
		return nil
	}
	return nil
}
